package com.example.keycloakstudy.controller;

import com.example.keycloakstudy.service.ProductService;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.security.Principal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Controller
class ProductController {

    @Autowired
    ProductService productService;

    private String serverUrl = "http://localhost:8080/auth";
    private String realm = "master";
    private String username = "admin";
    private String password = "111111";
    private String clientId = "product-app";

    @GetMapping(path = "/products")
    public String getProducts(HttpServletRequest request, Model model){
        model.addAttribute("products", productService.getProducts());
        return "product";
    }

    @GetMapping(path = "/products/iphone")
    @ResponseBody
    public Map getProductsiphone(Principal principal, Model model){
        Map map = new HashMap();
        if (principal instanceof KeycloakPrincipal) {
            KeycloakSecurityContext keycloakPrincipal =((KeycloakPrincipal) principal).getKeycloakSecurityContext();
            AccessToken accessToken = keycloakPrincipal.getToken();
            //获取用户名
            String preferredUsername = accessToken.getPreferredUsername();
            AccessToken.Access realmAccess = accessToken.getRealmAccess();

            //获取角色
            Set<String> roles = realmAccess.getRoles();
            map.put("username", preferredUsername);
            map.put("roles", roles);
            map.put("token", keycloakPrincipal.getTokenString());
        }
        return map;
    }

    /**
     * 创建用户
     * @return
     */
    @ResponseBody
    @GetMapping("/createUser")
    public String createUser(){
        Keycloak keycloak = Keycloak.getInstance(serverUrl, realm, username, password, clientId);
        UserRepresentation user = new UserRepresentation();
        user.setUsername("test2");

        CredentialRepresentation credential = new CredentialRepresentation();
        credential.setType(CredentialRepresentation.PASSWORD);
        credential.setValue("111111");//用户密码
        credential.setTemporary(false);//关闭下次登录更新密码

        user.setCredentials(Arrays.asList(credential));
        user.setEnabled(true);

//        List<String> realmRoles = new ArrayList<>();
//        realmRoles.add("user-role");
//        user.setRealmRoles(realmRoles);

//        user.setRequiredActions(Arrays.asList("Update Password"));
//        RealmRepresentation realmRepresentation = keycloak.realm(realm).toRepresentation();//获取域信息
//        System.out.println(realmRepresentation.getRealm());
        Response response = keycloak.realm(realm).users().create(user);

        if(response != null && response.getStatus() == 201){
            System.out.println("创建成功");
            return "success";
        }
        return "fail";
    }

    /**
     * 创建用户并关联角色
     * @return
     */
    @ResponseBody
    @GetMapping("/createUserAndRelRole")
    public String createUserAndRelRole(){
        Keycloak keycloak = Keycloak.getInstance(serverUrl, realm, username, password, clientId);
        UserRepresentation user = new UserRepresentation();
        user.setUsername("test2");

        CredentialRepresentation credential = new CredentialRepresentation();
        credential.setType(CredentialRepresentation.PASSWORD);
        credential.setValue("111111");//用户密码
        credential.setTemporary(false);//关闭下次登录更新密码

        user.setCredentials(Arrays.asList(credential));
        user.setEnabled(true);

        Response response = keycloak.realm(realm).users().create(user);
        //判断创建用户状态
        Response.StatusType createUserStatus = response.getStatusInfo();
        URI location = response.getLocation();
        System.out.println(createUserStatus);
        if ("Created".equals(createUserStatus.toString())) {
            System.out.println("创建用户成功！");
            System.out.println("创建用户的URI：" + location);

            //获取创建用户的userId
            String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");

            //关联指定角色
            RoleRepresentation testerRealmRole = keycloak.realm(realm).roles().get("user-role").toRepresentation();
            keycloak.realm(realm).users().get(userId).roles().realmLevel().add(Arrays.asList(testerRealmRole));

            if(response != null && response.getStatus() == 201){
                System.out.println("创建成功");
                return "success";
            }
        } else {
            throw new RuntimeException("账号已经存在！");
        }

        return "fail";
    }

    /**
     * 验证token
     * @return
     */
    @ResponseBody
    @PostMapping("/verifyToken")
    public String verifyToken(@RequestParam String token) {
        AccessToken accessToken = null;
        try {
            //1、设置client配置信息
            AdapterConfig adapterConfig = new AdapterConfig();
            //realm name
            adapterConfig.setRealm(realm);
            //client_id
            adapterConfig.setResource(clientId);
            //认证中心keycloak地址
            adapterConfig.setAuthServerUrl(serverUrl);
            //访问https接口时，禁用证书检查。
            adapterConfig.setDisableTrustManager(true);
            //2、根据client配置信息构建KeycloakDeployment对象
            KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(adapterConfig);
            //3、执行token签名验证和有效性检查（不通过会抛异常）
            accessToken = AdapterTokenVerifier.verifyToken(token, deployment);
        }catch (Exception e){
            e.printStackTrace();
        }
        if(accessToken!=null){
            return "success";
        }else{
            return "fail";
        }
    }

    /**
     * 登录
     * @return
     */
    @ResponseBody
    @GetMapping("/login")
    public String login() {
        Keycloak keycloak = Keycloak.getInstance(serverUrl, realm, "test2", "111111", "product-app");
        AccessTokenResponse accessTokenResponse = keycloak.tokenManager().getAccessToken();
        System.out.println(accessTokenResponse);
        return "login";
    }

    /**
     * 修改用户密码
     * @return
     */
    @ResponseBody
    @GetMapping("/resetPassword")
    public String resetPassword(Principal principal){
        if (principal instanceof KeycloakPrincipal) {
            AccessToken accessToken = ((KeycloakPrincipal) principal).getKeycloakSecurityContext().getToken();
            //获取用户id
            String id = principal.getName();
            Keycloak keycloak = Keycloak.getInstance(serverUrl, realm, username, password, clientId);

            CredentialRepresentation credential = new CredentialRepresentation();
            credential.setType(CredentialRepresentation.PASSWORD);
            credential.setValue("123456");//用户密码
            credential.setTemporary(false);//关闭下次登录更新密码

            keycloak.realm(realm).users().get(id).resetPassword(credential);
            return "success";
        }

        return "fail";
    }

    @GetMapping(path = "/logout")
    public String logout(HttpServletRequest request) throws ServletException {
        request.logout();
        return "index";
    }
}